home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 15 / Example 15.1 / network.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  11.5 KB  |  410 lines

  1. #include "network.h"
  2.  
  3. // {D962EEE5-7783-4018-9C0D-C326821F808F}, Unique application ID
  4. GUID RTS_APP_ID = { 0xd962eee5, 0x7783, 0x4018, {0x9c, 0xd, 0xc3, 0x26, 0x82, 0x1f, 0x80, 0x8f} };
  5.  
  6. NETWORK network;    //Global network variable
  7.  
  8. NETWORK::NETWORK()
  9. {
  10.     m_pServer = NULL;
  11.     m_pClient = NULL;
  12.     m_pMyAddress = NULL;
  13.     m_pServerAddress = NULL;
  14. }
  15.  
  16. NETWORK::~NETWORK()
  17. {
  18.     Release();
  19. }
  20.  
  21. void NETWORK::Init(bool _server, char _playerName[])
  22. {
  23.     try
  24.     {
  25.         server = _server;
  26.         CoInitialize(NULL);
  27.         strcpy(playerName, _playerName);
  28.         connected = false;
  29.  
  30.         if(server)        //Init Server
  31.         {
  32.             if(FAILED(CoCreateInstance(CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Server, (LPVOID*)&m_pServer)))debug.Print("Failed to Create Server.\n");
  33.             if(FAILED(m_pServer->Initialize(NULL, ServerCallback, 0)))debug.Print("Failed to Init Server.\n");
  34.         }
  35.         else            //Init Client
  36.         {
  37.             if(FAILED(CoCreateInstance(CLSID_DirectPlay8Client, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Client, (LPVOID*)&m_pClient)))debug.Print("Failed to Create Client.\n");
  38.             if(FAILED(m_pClient->Initialize(NULL, ClientCallback, 0)))debug.Print("Failed to Init Client.\n");
  39.         }
  40.  
  41.         //Create My address
  42.         if(FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_ALL, IID_IDirectPlay8Address, (LPVOID*)&m_pMyAddress)))debug.Print("Failed to Create m_pMyAddress.\n");
  43.         if(FAILED(m_pMyAddress->SetSP(&CLSID_DP8SP_TCPIP)))debug.Print("Failed to set Service Protocol");
  44.  
  45.         //Create Server address
  46.         if(FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_ALL, IID_IDirectPlay8Address, (LPVOID*)&m_pServerAddress)))debug.Print("Failed to Create m_pServerAddress.\n");
  47.         if(FAILED(m_pServerAddress->SetSP(&CLSID_DP8SP_TCPIP)))debug.Print("Failed to set Service Protocol");
  48.  
  49.         CoUninitialize();
  50.     }
  51.     catch(...)
  52.     {
  53.         debug.Print("Error in NETWORK::Init()");
  54.     }
  55. }
  56.  
  57. void NETWORK::Release()
  58. {
  59.     try
  60.     {
  61.         if(m_pMyAddress)m_pMyAddress->Release();
  62.         if(m_pServerAddress)m_pServerAddress->Release();
  63.         m_pMyAddress = NULL;
  64.         m_pServerAddress = NULL;        
  65.  
  66.         //Close connections
  67.         if(m_pServer)
  68.         {
  69.             m_pServer->Close(DPNCLOSE_IMMEDIATE);
  70.             m_pServer = NULL;
  71.         }
  72.         if(m_pClient)
  73.         {
  74.             m_pClient->Close(DPNCLOSE_IMMEDIATE);
  75.             m_pClient = NULL;
  76.         }
  77.     }
  78.     catch(...)
  79.     {
  80.         debug.Print("Error in NETWORK::Release()");
  81.     }
  82. }
  83.  
  84. void NETWORK::HostNewSession(char sessionName[])
  85. {
  86.     try
  87.     {
  88.         WCHAR strHost[128];
  89.         DPN_APPLICATION_DESC desc;
  90.         mbstowcs(strHost, sessionName, strlen(sessionName) + 1);
  91.         strcpy(activeSession, sessionName);
  92.  
  93.         // Set up the Application Description.
  94.         ZeroMemory(&desc, sizeof(DPN_APPLICATION_DESC));
  95.         desc.dwSize = sizeof(DPN_APPLICATION_DESC);
  96.         desc.dwFlags = DPNSESSION_CLIENT_SERVER;    // Flag describing the app
  97.         desc.guidApplication = RTS_APP_ID;          // GUID for the app
  98.         desc.pwszSessionName = strHost;                // Session name
  99.  
  100.         // Host the application.
  101.         if(FAILED(m_pServer->Host(&desc, &m_pMyAddress, 1, NULL, NULL, this, 0)))
  102.             debug.Print("Failed to host session");
  103.         else connected = true;
  104.     }
  105.     catch(...)
  106.     {
  107.         debug.Print("Error in NETWORK::HostNewSession()");
  108.     }
  109. }
  110.  
  111. void NETWORK::FindSessions()
  112. {
  113.     if(m_pClient == NULL)return;
  114.  
  115.     sessions.clear();
  116.  
  117.     //Setup what kind of sessions you are looking for
  118.     DPN_APPLICATION_DESC desc;
  119.     ZeroMemory(&desc, sizeof(DPN_APPLICATION_DESC));
  120.     desc.dwSize = sizeof(DPN_APPLICATION_DESC);
  121.     desc.guidApplication = RTS_APP_ID;
  122.  
  123.     if(FAILED(m_pClient->EnumHosts(&desc,     // pApplicationDesc
  124.                            m_pServerAddress,       // Host Address
  125.                            m_pMyAddress,           // Device Address
  126.                            NULL, 0,             // pvUserEnumData, size
  127.                            1,                   // dwEnumCount
  128.                            0,                   // dwRetryInterval
  129.                            0,                   // dwTimeOut
  130.                            NULL,                // pvUserContext
  131.                            NULL,                // pAsyncHandle
  132.                            DPNENUMHOSTS_SYNC))) // dwFlags
  133.         debug.Print("Failed to enumerate Sessions");
  134. }
  135.  
  136. HRESULT NETWORK::ConnectToSession(int index)
  137. {
  138.     if(index < 0 || index >= sessions.size() || m_pClient == NULL)
  139.     {
  140.         debug.Print("Not correct session to connect to, or m_pClient is NULL");
  141.         return E_FAIL;
  142.     }
  143.  
  144.     strcpy(activeSession, sessions[index].name.c_str());
  145.  
  146.     HRESULT hr = m_pClient->Connect(&sessions[index].desc,    // pdnAppDesc
  147.                                   sessions[index].address,      // pHostAddr
  148.                                   m_pMyAddress,                    // pDeviceInfo
  149.                                   NULL,                            // pdnSecurity
  150.                                   NULL,                            // pdnCredentials
  151.                                   NULL, 0,                        // pvUserConnectData, Size
  152.                                   NULL,                            // pvAsyncContext
  153.                                   NULL,                            // pvAsyncHandle
  154.                                   DPNCONNECT_SYNC);                // dwFlags
  155.  
  156.     if(SUCCEEDED(hr))connected = true;
  157.  
  158.     return hr;
  159. }
  160.  
  161. DP_PLAYER* NETWORK::FindPlayer(DPNID id)
  162. {
  163.     //Finds a player in the player vector with matching ID
  164.     for(int i=0;i<network.players.size();i++)
  165.         if(network.players[i].id == id)
  166.             return &network.players[i];
  167.  
  168.     return NULL;
  169. }
  170.  
  171. void NETWORK::Send(RTS_MSG *msg)
  172. {
  173.     //Sends the message to all players
  174.     SendTo(DPNID_ALL_PLAYERS_GROUP, msg);
  175. }
  176.  
  177. void NETWORK::SendTo(DPNID id, RTS_MSG *msg)
  178. {
  179.     try
  180.     {
  181.         DPN_BUFFER_DESC desc;
  182.         desc.pBufferData = (BYTE*)msg;
  183.         
  184.         //Message size
  185.         if(msg->type == GAME_MSG_TEXT)
  186.             desc.dwBufferSize = sizeof(MSG_TEXT);
  187.         else if(msg->type == GAME_MSG_COMMAND)
  188.             desc.dwBufferSize = sizeof(MSG_COMMAND);
  189.         else if(msg->type == GAME_MSG_PLAYER)
  190.             desc.dwBufferSize = sizeof(MSG_PLAYER);
  191.  
  192.         if(server && m_pServer)
  193.         {
  194.             m_pServer->SendTo(id,                          // dpnid
  195.                                 &desc,                      // pBufferDesc
  196.                                 1,                        // cBufferDesc
  197.                                 0,                        // dwTimeOut
  198.                                 NULL,                     // pvAsyncContext
  199.                                 NULL,                     // pvAsyncHandle
  200.                                 DPNSEND_SYNC |            // dwFlags
  201.                                 DPNSEND_NOLOOPBACK);    
  202.         }
  203.         else if(m_pClient)
  204.         {
  205.             m_pClient->Send(&desc,                    // pBufferDesc
  206.                             1,                      // cBufferDesc
  207.                             0,                      // dwTimeOut
  208.                             NULL,                   // pvAsyncContext
  209.                             NULL,                   // pvAsyncHandle
  210.                             DPNSEND_SYNC |
  211.                             DPNSEND_NOLOOPBACK);    // dwFlags
  212.         }
  213.     }
  214.     catch(...)
  215.     {
  216.         debug.Print("Error in NETWORK::SendTo()");
  217.     }
  218. }
  219.  
  220. HRESULT WINAPI ServerCallback(PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage)
  221. {
  222.     try
  223.     {
  224.         switch(dwMessageType)
  225.         {
  226.             case DPN_MSGID_CREATE_PLAYER:        //New player has connected
  227.             {
  228.                 PDPNMSG_CREATE_PLAYER msg = (PDPNMSG_CREATE_PLAYER)pMessage;
  229.  
  230.                 if(msg->pvPlayerContext == &network)    //Local player
  231.                 {
  232.                     network.m_localID = msg->dpnidPlayer;
  233.                     network.players.push_back(DP_PLAYER(msg->dpnidPlayer, network.playerName));
  234.                 }
  235.                 else
  236.                 {
  237.                     //Ask for new players name
  238.                     MSG_COMMAND cmd(0, 0);
  239.                     network.SendTo(msg->dpnidPlayer, &cmd);
  240.                 }
  241.  
  242.                 break;
  243.             }
  244.             case DPN_MSGID_DESTROY_PLAYER:        //Player has left the game
  245.             {
  246.                 PDPNMSG_DESTROY_PLAYER msg = (PDPNMSG_DESTROY_PLAYER)pMessage;
  247.                 
  248.                 DP_PLAYER *player = network.FindPlayer(msg->dpnidPlayer);
  249.                 if(player != NULL)
  250.                 {
  251.                     MSG_PLAYER play(*player, 1);
  252.                     network.Send(&play);
  253.                     network.players.erase(player);
  254.                 }
  255.  
  256.                 break;
  257.             }
  258.             case DPN_MSGID_TERMINATE_SESSION:    //Session terminated
  259.             {
  260.                 network.players.clear();
  261.                 network.connected = false;
  262.  
  263.                 break;
  264.             }
  265.             case DPN_MSGID_RECEIVE:        //Data received
  266.             {
  267.                 PDPNMSG_RECEIVE data = (PDPNMSG_RECEIVE)pMessage;
  268.                 RTS_MSG *msg = (RTS_MSG*)data->pReceiveData;
  269.                 DP_PLAYER *player = network.FindPlayer(data->dpnidSender);
  270.  
  271.                 switch(msg->type)
  272.                 {
  273.                     case GAME_MSG_TEXT:        //Text message
  274.                     {
  275.                         MSG_TEXT *textMessage = (MSG_TEXT*)msg;
  276.                         network.chat.push_back(textMessage->text);
  277.                         if(network.chat.size() > 20)network.chat.erase(network.chat.begin());
  278.  
  279.                         //Relay text message to other players
  280.                         network.Send(msg);
  281.                         break;
  282.                     }
  283.                     case GAME_MSG_COMMAND:        //Game Command
  284.                     {
  285.  
  286.                         break;
  287.                     }
  288.                     case GAME_MSG_PLAYER:        //Add, Remove players etc...
  289.                     {        
  290.                         MSG_PLAYER *playerMessage = (MSG_PLAYER*)msg;
  291.  
  292.                         if(playerMessage->operation == 2)        //Get Name
  293.                         {
  294.                             network.players.push_back(DP_PLAYER(data->dpnidSender, playerMessage->player.name));
  295.  
  296.                             //Send all other players to the new player...
  297.                             for(int i=0;i<network.players.size();i++)
  298.                             {
  299.                                 MSG_PLAYER ply(network.players[i], 0);
  300.                                 network.SendTo(data->dpnidSender, &ply);
  301.                             }
  302.  
  303.                             MSG_PLAYER newPlayer(network.players[network.players.size() - 1], 0);
  304.                             network.Send(&newPlayer);
  305.                         }
  306.                         break;
  307.                     }
  308.                 }
  309.  
  310.                 break;
  311.             }
  312.         }
  313.  
  314.         return S_OK;
  315.     }
  316.     catch(...)
  317.     {
  318.         debug.Print("Error in ServerCallback()");
  319.         return E_FAIL;
  320.     }
  321. }
  322.  
  323. HRESULT WINAPI ClientCallback(PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage)
  324. {
  325.     try
  326.     {
  327.         switch(dwMessageType)
  328.         {
  329.             case DPN_MSGID_ENUM_HOSTS_RESPONSE:        // Enumerate sessions responses
  330.             {
  331.                 PDPNMSG_ENUM_HOSTS_RESPONSE msg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMessage;
  332.                 const DPN_APPLICATION_DESC* desc = msg->pApplicationDescription;
  333.                 char sessionName[128];
  334.                 wcstombs(sessionName, desc->pwszSessionName, wcslen(desc->pwszSessionName) + 1);
  335.                 network.sessions.push_back(SESSION(sessionName, *desc, msg->pAddressSender));
  336.                 break;
  337.             }
  338.             case DPN_MSGID_TERMINATE_SESSION:        //Server died, or some such...
  339.             {
  340.                 network.players.clear();
  341.                 network.connected = false;
  342.  
  343.                 break;
  344.             }
  345.             case DPN_MSGID_RECEIVE:            //Data...
  346.             {
  347.                 PDPNMSG_RECEIVE data = (PDPNMSG_RECEIVE)pMessage;
  348.                 RTS_MSG *msg = (RTS_MSG*)data->pReceiveData;
  349.                 DP_PLAYER *player = network.FindPlayer(data->dpnidSender);
  350.  
  351.                 switch(msg->type)
  352.                 {
  353.                     case GAME_MSG_TEXT:        //Chat/text message
  354.                     {
  355.                         MSG_TEXT *textMessage = (MSG_TEXT*)msg;
  356.                         network.chat.push_back(textMessage->text);
  357.                         if(network.chat.size() > 20)network.chat.erase(network.chat.begin());
  358.  
  359.                         break;
  360.                     }
  361.                     case GAME_MSG_COMMAND:        //Game command
  362.                     {
  363.                         MSG_COMMAND *cmd = (MSG_COMMAND*)msg;
  364.  
  365.                         if(cmd->command == 0)        //Ask for name
  366.                         {
  367.                             MSG_PLAYER play(DP_PLAYER(0, network.playerName), 2);
  368.                             network.Send(&play);
  369.                         }
  370.  
  371.                         break;
  372.                     }
  373.                     case GAME_MSG_PLAYER:        //Add, Remove, Update Name of players...
  374.                     {
  375.                         MSG_PLAYER *playerMessage = (MSG_PLAYER*)msg;
  376.  
  377.                         if(playerMessage->operation == 0)    //Add Player
  378.                         {
  379.                             DP_PLAYER *oldPlayer = network.FindPlayer(playerMessage->player.id);
  380.  
  381.                             if(oldPlayer == NULL)
  382.                             {
  383.                                 network.players.push_back(playerMessage->player);
  384.                                 printf("Player %s joined game\n", playerMessage->player.name);
  385.                             }
  386.                         }
  387.                         else if(playerMessage->operation == 1)    //Remove Player
  388.                         {
  389.                             DP_PLAYER *playerToErase = network.FindPlayer(playerMessage->player.id);
  390.                             if(playerToErase != NULL)network.players.erase(playerToErase);
  391.                         }
  392.                         if(playerMessage->operation == 2 && player)        //Update Name
  393.                             strcpy(player->name, playerMessage->player.name);
  394.  
  395.                         break;
  396.                     }
  397.                 }
  398.  
  399.                 break;
  400.             }
  401.         }
  402.  
  403.         return S_OK;
  404.     }
  405.     catch(...)
  406.     {
  407.         debug.Print("Error in ClientCallback()");
  408.         return E_FAIL;
  409.     }
  410. }